﻿using AlibabaCloud.SDK.Alidns20150109;
using AlibabaCloud.SDK.Alidns20150109.Models;
using AlibabaCloud.OpenApiClient.Models;
using Tea;

namespace xrwang.DDNS.Aliyun
{
    /// <summary>
    /// 阿里云域名记录操作
    /// </summary>
    public class DomainRecordOperator : IDomainRecordOperator
    {
        #region Const
        /// <summary>
        /// 默认的记录线路
        /// </summary>
        public const string DEFAULT_RECORD_LINE = "default";
        #endregion Const

        /// <summary>
        /// 密匙id
        /// </summary>
        private string accessKeyID;
        /// <summary>
        /// 密匙id
        /// </summary>
        public string AccessKeyID
        {
            get
            {
                return accessKeyID;
            }
            set
            {
                if (string.IsNullOrWhiteSpace(value))
                    throw new ArgumentNullException(nameof(AccessKeyID), string.Format("{0}不能为空。", nameof(AccessKeyID)));
                accessKeyID = value;
                CreateClient();
            }
        }
        /// <summary>
        /// 密匙
        /// </summary>
        private string accessKeySecret;
        /// <summary>
        /// 密匙
        /// </summary>
        public string AccessKeySecret
        {
            get
            {
                return accessKeySecret;
            }
            set
            {
                if (string.IsNullOrWhiteSpace(value))
                    throw new ArgumentNullException(nameof(AccessKeySecret), string.Format("{0}不能为空。", nameof(AccessKeySecret)));
                accessKeySecret = value;
                CreateClient();
            }
        }
        /// <summary>
        /// 客户端
        /// </summary>
        private Client client;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="accessKeyID">密匙id</param>
        /// <param name="accessKeySecret">密匙</param>
        public DomainRecordOperator(string accessKeyID, string accessKeySecret)
        {
            if (string.IsNullOrWhiteSpace(accessKeyID))
                throw new ArgumentNullException(nameof(AccessKeyID), string.Format("{0}不能为空。", nameof(AccessKeyID)));
            this.accessKeyID = accessKeyID;
            if (string.IsNullOrWhiteSpace(accessKeySecret))
                throw new ArgumentNullException(nameof(AccessKeySecret), string.Format("{0}不能为空。", nameof(AccessKeySecret)));
            this.accessKeySecret = accessKeySecret;
            CreateClient();
        }

        /// <summary>
        /// 创建客户端
        /// </summary>
        private void CreateClient() 
        {
            if (string.IsNullOrWhiteSpace(accessKeyID) || string.IsNullOrWhiteSpace(accessKeySecret))
                client = null;
            else
                client = new Client(new Config()
                {
                    AccessKeyId = accessKeyID,
                    AccessKeySecret = accessKeySecret
                });
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="recordId">记录id</param>
        /// <param name="domainName">域名（阿里云域名记录删除接口不需要该参数）</param>
        /// <returns>返回结果。如果成功，Data为请求id。</returns>
        public async Task<ActionResult<string>> DeleteAsync(string recordId, string domainName = "")
        {
            DeleteDomainRecordRequest request = new DeleteDomainRecordRequest()
            {
                RecordId = recordId
            };
            try
            {
                DeleteDomainRecordResponse response = await client.DeleteDomainRecordAsync(request);
                return new ActionResult<string>(true, "", response.Body.RequestId);
            }
            catch (TeaException e)
            {
                return new ActionResult<string>(false, e.Message);
            }
            catch (Exception e)
            {
                return new ActionResult<string>(false, e.Message);
            }
        }

        /// <summary>
        /// 获取域名记录列表
        /// </summary>
        /// <param name="domainName">域名名称</param>
        /// <param name="rr">主机记录</param>
        /// <param name="type">记录类型</param>
        /// <param name="value">记录值</param>
        /// <param name="line">解析线路</param>
        /// <param name="page">页码</param>
        /// <param name="pageSize">每页记录数</param>
        /// <returns>返回结果。如果成功，Data1为域名记录信息列表，Data2为记录总数。</returns>
        public async Task<ActionResult<List<DomainRecordInfo>, int>> GetListAsync(string domainName, string rr = "", DomainRecordTypeEnum? type = null, string value = "", string line = "", int page = 1, int pageSize = 100)
        {
            DescribeDomainRecordsRequest request = new DescribeDomainRecordsRequest()
            {
                DomainName = domainName,
                RRKeyWord = rr,
                Type = type.HasValue ? type.Value.ToString("g") : "",
                ValueKeyWord = value,
                Line = line,
                PageNumber = page,
                PageSize = pageSize
            };
            try
            {
                DescribeDomainRecordsResponse response = await client.DescribeDomainRecordsAsync(request);
                return new ActionResult<List<DomainRecordInfo>, int>(true, "",
                    response.Body.DomainRecords == null || response.Body.DomainRecords.Record == null ? null : response.Body.DomainRecords.Record.Select(rec => new DomainRecordInfo()
                    {
                        RecordId = rec.RecordId,
                        DomainName = rec.DomainName,
                        RR = rec.RR,
                        Type = rec.Type,
                        Value = rec.Value,
                        TTL = rec.TTL,
                        Priority = rec.Priority,
                        Line = rec.Line,
                        Locked = rec.Locked,
                        Status = rec.Status == DomainRecordStatusEnum.Enable.ToString("g")
                    }).ToList(),
                    response.Body.TotalCount.HasValue ? (int)response.Body.TotalCount.Value : 0);
            }
            catch (TeaException e)
            {
                return new ActionResult<List<DomainRecordInfo>, int>(false, e.Message, null, 0);
            }
            catch (Exception e)
            {
                return new ActionResult<List<DomainRecordInfo>, int>(false, e.Message, null, 0);
            }
        }

        /// <summary>
        /// 设置状态
        /// </summary>
        /// <param name="recordId">记录id</param>
        /// <param name="domainName">域名名称（阿里云域名记录删除接口不需要该参数）</param>
        /// <returns>返回结果。如果成功，Data为请求id。</returns>
        public async Task<ActionResult<string>> SetStatusAsync(string recordId, string domainName = "", bool enabled = true)
        {
            SetDomainRecordStatusRequest request = new SetDomainRecordStatusRequest()
            {
                RecordId = recordId,
                Status = (enabled ? DomainRecordStatusEnum.Enable : DomainRecordStatusEnum.Disable).ToString("g")
            };
            try
            {
                SetDomainRecordStatusResponse response = await client.SetDomainRecordStatusAsync(request);
                return new ActionResult<string>(true, "", response.Body.RequestId);
            }
            catch (TeaException e)
            {
                return new ActionResult<string>(false, e.Message);
            }
            catch (Exception e)
            {
                return new ActionResult<string>(false, e.Message);
            }
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="record">域名记录</param>
        /// <returns>返回结果。如果成功，Data1为请求id，Data2为记录id。</returns>
        public async Task<ActionResult<string, string>> AddAsync(DomainRecordInfo record)
        {
            AddDomainRecordRequest request = new AddDomainRecordRequest()
            {
                DomainName = record.DomainName,
                RR = record.RR,
                Type = record.Type,
                Value = record.Value,
                TTL = record.TTL,
                Priority = record.Priority,
                Line = string.IsNullOrWhiteSpace(record.Line) ? DEFAULT_RECORD_LINE : record.Line,
            };
            try
            {
                AddDomainRecordResponse response = await client.AddDomainRecordAsync(request);
                if (!record.Status)
                    await SetStatusAsync(response.Body.RecordId, record.DomainName, record.Status);
                return new ActionResult<string, string>(true, "", response.Body.RequestId, response.Body.RecordId);
            }
            catch (TeaException e)
            {
                return new ActionResult<string, string>(false, e.Message);
            }
            catch (Exception e)
            {
                return new ActionResult<string, string>(false, e.Message);
            }
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="record">域名记录</param>
        /// <returns>返回结果。如果成功，Data1为请求id，Data2为记录id。</returns>
        public async Task<ActionResult<string, string>> UpdateAsync(DomainRecordInfo record)
        {
            UpdateDomainRecordRequest request = new UpdateDomainRecordRequest()
            {
                RecordId = record.RecordId,
                RR = record.RR,
                Type = record.Type,
                Value = record.Value,
                TTL = record.TTL,
                Priority = record.Priority,
                Line = string.IsNullOrWhiteSpace(record.Line) ? DEFAULT_RECORD_LINE : record.Line,
            };
            try
            {
                UpdateDomainRecordResponse response = await client.UpdateDomainRecordAsync(request);
                await SetStatusAsync(record.RecordId, record.DomainName, record.Status);
                return new ActionResult<string, string>(true, "", response.Body.RequestId, response.Body.RecordId);
            }
            catch (TeaException e)
            {
                return new ActionResult<string, string>(false, e.Message);
            }
            catch (Exception e)
            {
                return new ActionResult<string, string>(false, e.Message);
            }
        }

        /// <summary>
        /// 保存
        /// </summary>
        /// <param name="record">域名记录</param>
        /// <returns>返回结果。如果成功，Data1为请求id，Data2为记录id。</returns>
        public async Task<ActionResult<string, string>> SaveAsync(DomainRecordInfo record)
        {
            ActionResult<List<DomainRecordInfo>, int> result = await GetListAsync(record.DomainName, record.RR);
            DomainRecordInfo rec = result.Success && result.Data1 != null ? result.Data1.FirstOrDefault(r => string.Compare(r.RR, record.RR, true) == 0) : null;
            if (rec != null)
            {
                record.RecordId = rec.RecordId;
                if (string.Compare(rec.Value, record.Value, true) != 0)
                    return await UpdateAsync(record);
                else if (rec.Status != record.Status)
                {
                    ActionResult<string> resultSetStatus = await SetStatusAsync(record.RecordId, record.DomainName, record.Status);
                    return new ActionResult<string, string>(resultSetStatus.Success, resultSetStatus.Message, resultSetStatus.Data, record.RecordId);
                }
                else
                    return new ActionResult<string, string>(true, "域名记录没有变化。");
            }
            else
                return await AddAsync(record);
        }
    }
}